home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 355_02 / slk2.exe / SPP / DIR.C < prev    next >
C/C++ Source or Header  |  1991-06-09  |  22KB  |  1,093 lines

  1. /*
  2.     New Sherlock Preprocessor -- directives
  3.  
  4.     source:  dir.c
  5.     started: October 7, 1985
  6.     version: July 20, 1988; June 9, 1991
  7.         June 9, 1991: bug fix to pp_elif
  8.          February 10, 1989:  bug fix in pp_include.
  9.          February 16, 1989:  periods removed from error messages.
  10.          March 3, 1989: fix bug in do_pp.
  11.  
  12.     External routines defined in this file: do_pp
  13.  
  14.  
  15.     PUBLIC DOMAIN SOFTWARE
  16.  
  17.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  18.     the public domain on June 15, 1991, by its author,
  19.  
  20.         Edward K. Ream
  21.         166 North Prospect Ave.
  22.         Madison, WI 53705.
  23.         (608) 257-0802
  24.  
  25.     Sherlock may be used for any commercial or non-commercial purpose.
  26.  
  27.  
  28.     DISCLAIMER OF WARRANTIES
  29.  
  30.     Edward K. Ream (Ream) specifically disclaims all warranties,
  31.     expressed or implied, with respect to this computer software,
  32.     including but not limited to implied warranties of merchantability
  33.     and fitness for a particular purpose.  In no event shall Ream be
  34.     liable for any loss of profit or any commercial damage, including
  35.     but not limited to special, incidental consequential or other damages.
  36. */
  37.  
  38. #include "spp.h"
  39.  
  40. #define TRACE_LINE(name) TRACEP(name, printf("line %d\n", t_line))
  41.  
  42. static long    eval        (void);
  43. static long     eval1        (void);
  44. static bool    gt_prec        (en_tokens, en_tokens);
  45. static bool    isfnch        (int, en_tokens);
  46.  
  47. static void    pp_elif        (void);
  48. static void    pp_else        (void);
  49. static void    pp_endif    (void);
  50. static void    pp_enum        (void);
  51. static void    pp_error    (void);
  52. static void    pp_if        (void);
  53. static void    pp_ifdef    (bool);
  54. static void    pp_incl        (void);
  55. static void    pp_line        (void);
  56. static void    pp_undef    (void);
  57. static int    prec        (int);
  58.  
  59. static void    push_op        (en_tokens);
  60. static en_tokens pop_op        (void);
  61. static void    push_val    (long);
  62. static long    pop_val        (void);
  63. static void    skip_lines    (void);
  64.  
  65. typedef enum {
  66.     IF_BEGIN = 0,
  67.     IF_ELSE  = 1,
  68.     IF_ELIF  = 2
  69. } if_state;
  70.  
  71. #define MAX_IF 50
  72.  
  73. static if_state if_stack [ MAX_IF ];
  74. static int        if_level = 0;
  75.  
  76.  
  77. /*
  78.     Do one preprocessor directive.
  79. */
  80.  
  81. #define EQL(string) str_eq(t_symbol+1,string+1)
  82.  
  83. void
  84. do_pp()
  85. {
  86.     TICK("do_pp");
  87.     syshflush();
  88.  
  89.     skip_ws(FALSE);
  90.  
  91.     /* Get the directive into t_symbol[]. */
  92.     if (!isalpha(ch)) {
  93.         goto not_alpha;
  94.     }
  95.     t_id(t_symbol, MAX_SYMBOL);
  96.  
  97.  
  98.     /* 3/3/89 */
  99.     skip_ws(FALSE);
  100.  
  101.     /* Skip simple white space after the directive. */
  102.     /* -----
  103.     while (ch == ' ' || ch == '\t') {
  104.         sysnext();
  105.     }
  106.     ----- */
  107.  
  108.     switch(t_symbol [0]) {
  109.  
  110.     case 'd':
  111.         if (t_length == 6 && EQL("define")) {
  112.             pp_def();
  113.             return;
  114.         }
  115.         goto not_pp;
  116.  
  117.     case 'e':
  118.         if (t_length == 4) {
  119.             if (EQL("else")) {
  120.                 pp_else();
  121.                 return;
  122.             }
  123.             else if (EQL("elif")) {
  124.                 pp_elif();
  125.                 return;
  126.             }
  127.         }
  128. #ifdef HAS_PP_ENUM
  129.         else if (t_length == 4 && EQL("enum")) {
  130.             pp_enum();
  131.             return;
  132.         }
  133. #endif
  134.         else if (t_length == 5 && EQL("endif")) {
  135.             pp_endif();
  136.             return;
  137.         }
  138.         else if (t_length == 5 && EQL("error")) {
  139.             pp_error();
  140.             return;
  141.         }
  142.         goto not_pp;
  143.  
  144.     case 'i':
  145.         switch(t_length) {
  146.         case 2:    if (EQL("if")) {
  147.                 pp_if();
  148.                 return;
  149.             }
  150.             goto not_pp;
  151.         case 5:    if (EQL("ifdef")) {
  152.                 pp_ifdef(TRUE);
  153.                 return;
  154.             }
  155.             goto not_pp;
  156.         case 6:    if (EQL("ifndef")) {
  157.                 pp_ifdef(FALSE);
  158.                 return;
  159.             }
  160.             goto not_pp;
  161.         case 7:    if (EQL("include")) {
  162.                 pp_incl();
  163.                 return;
  164.             }
  165.             goto not_pp;
  166.         }
  167.         goto not_pp;
  168.  
  169.     case 'l':
  170.         if (t_length == 4 && EQL("line")) {
  171.             pp_line();
  172.             return;
  173.         }
  174.         goto not_pp;
  175.  
  176.     case 'p':
  177.         if (t_length == 6 && EQL("pragma")) {
  178.             /* Do NOTHING!! */
  179.             skip_pp();
  180.             return;
  181.         }
  182.         goto not_pp;
  183.     
  184.     case 'u':
  185.         if (t_length == 5 && EQL("undef")) {
  186.             pp_undef();
  187.             return;
  188.         }
  189.         goto not_pp;
  190.  
  191.     default:
  192.         goto not_pp;
  193.     }
  194.     
  195. not_alpha:
  196.     /*
  197.         Be more permissive than the new C standard.
  198.         Just skip the rest of the line.
  199.     */
  200.     skip_pp();
  201.     return;
  202.  
  203. not_pp:
  204.     err2(t_symbol, " is not a valid preprocessor directive");
  205.     skip_pp();
  206. }
  207.  
  208. #undef EQL
  209.  
  210. /*
  211.     Handle the #error directive.
  212.     Instead of producing a diagnostic message, just copy it.
  213. */
  214. static void
  215. pp_error()
  216. {
  217.     skip_pp();
  218. }
  219.         
  220.     
  221. /*
  222.     Evaluate a constant expression to either true or false.
  223.     A constant expression consists of:
  224.  
  225.     1. integer constants or character constants
  226.     2. the unary - + and ~ operators
  227.     3. the binary + - * / & | ^ << >> == != < > <= >= oprators
  228.     4. the ternary ? : operator
  229.     5. the ( and ) groupers.
  230.  
  231.     Identifiers are expanded if they are defined, otherwise they
  232.     are taken to have a value of zero. All arithmetic is integer and
  233.     ints are expanded to long.
  234. */
  235.  
  236. #define MAX_EVAL_VAL 100
  237. #define MAX_EVAL_OP 50
  238.  
  239. static    long         val_stack[MAX_EVAL_VAL];
  240. static    int        val_ptr = 0;
  241. static    en_tokens    op_stack[MAX_EVAL_OP];
  242. static    int        op_ptr = 0;
  243. static long result;
  244. static bool paren_seen;
  245. static bool error_seen;
  246.  
  247. static long
  248. eval()
  249. {
  250.     TRACETOK("eval");
  251.  
  252.     error_seen = FALSE;
  253.     con_flag   = TRUE;
  254.     get_token();
  255.     result = eval1();
  256.     con_flag   = FALSE;
  257.  
  258.     RETURN_LONG("eval", result);
  259. }
  260.  
  261. static char    * junk;
  262. static int    junki;
  263.  
  264. static long
  265. eval1()
  266. {
  267.     register en_tokens op, op2;
  268.     register long val1, val2, val3;
  269.     int op_1ptr;
  270.  
  271.     TRACETOK("eval1");
  272.  
  273.     op_1ptr  = op_ptr;
  274.  
  275.     /* State S1: unary +, unary -, !, ~, constant or id is expected here. */
  276.  
  277. s1:
  278.     TRACEPN("v_eval1", printf("at state 1\n"));
  279.  
  280.     while (is(PLUS_TOK) || is(MINUS_TOK) || is(TILDE_TOK) || is(NOT_TOK)) {
  281.         if (is(PLUS_TOK)) {
  282.             push_op(UPLUS_TOK);
  283.         }
  284.         else if (is(MINUS_TOK)) {
  285.             push_op(UMINUS_TOK);
  286.         }
  287.         else if (is(NOT_TOK)) {
  288.             push_op(NOT_TOK);
  289.         }
  290.         else {
  291.             push_op(TILDE_TOK);
  292.         }
  293.         get_token();
  294.     }
  295.  
  296.     /* We expect a constant or identifier here. */
  297.     if (is(INT_TOK) || is(LONG_TOK) || is(CHAR_TOK)) {
  298.         push_val((long) t_value);
  299.         get_token();
  300.     }
  301.     else if (is(ID_TOK)) {
  302.         /* Special case defined id and defined(id). */
  303.         if (str_eq(t_symbol, "defined")) {
  304.  
  305.             /* Do not macro expand an id here! */
  306.             get_xtoken();
  307.             if (!is(ID_TOK) && !is(LPAREN_TOK)) {
  308.                 error("Id or '(' expected after 'defined'");
  309.                 goto bad_expr;
  310.             }
  311.             paren_seen = is(LPAREN_TOK);
  312.             if (paren_seen) {
  313.                 get_xtoken();
  314.                 if (!is(ID_TOK)) {
  315.                     error("Id expected after '('");
  316.                     goto bad_expr;
  317.                 }
  318.             }
  319.             if(mst_lookup(t_symbol, &junk, &junki)) {
  320.                 push_val(1L);
  321.             }
  322.             else {
  323.                 push_val(0L);
  324.             }
  325.             get_token();
  326.             if (paren_seen) {
  327.                 if (is(RPAREN_TOK)) {
  328.                     get_token();
  329.                 }
  330.                 else {
  331.                     error("')' expected");
  332.                     goto bad_expr;
  333.                 }
  334.             }
  335.         }
  336.         else {
  337.             /* The identifier must be undefined, so it gets 0. */
  338.             push_val(0L);
  339.             get_token();
  340.         }
  341.     }
  342.     else if (is(LPAREN_TOK)) {
  343.         get_token();
  344.  
  345.         /* Evaluate the expression recursively. */        
  346.         result = eval1();
  347.         if (is(RPAREN_TOK)) {
  348.             get_token();
  349.             push_val(result);
  350.         }
  351.         else {
  352.             error("')' expected");
  353.             goto bad_expr;
  354.         }
  355.     }        
  356.     else {
  357.         error("Integer constant or parenthesized expression expected");
  358.         goto bad_expr;
  359.     }
  360.  
  361.     /* Perform all unary ops and enter state S2. */
  362.     TRACEPN("v_eval1", printf("at state 1A\n"));
  363.     while (op_ptr > op_1ptr) {
  364.         switch (op = pop_op()) {
  365.         case UPLUS_TOK:     break;
  366.         case UMINUS_TOK: push_val(-pop_val());        break;
  367.         case NOT_TOK:     push_val((long)(!pop_val()));    break;
  368.         case TILDE_TOK:     push_val(~pop_val());        break;
  369.         default:     push_op(op);            goto s2;
  370.         }
  371.     }
  372.  
  373.     /* State S2: binary op or end_of_expression expected here. */
  374.  
  375. s2:
  376.     TRACEPN("v_eval1", printf("at state 2\n"));
  377.  
  378.     /*
  379.         Perform binary operators until the operator stack is
  380.         empty or until token operator has a higher precedence
  381.         than the operator on the top of the operator stack.
  382.     */
  383.  
  384.     while (op_ptr > op_1ptr && gt_prec(op_stack[op_ptr - 1], token)) {
  385.  
  386.         val2 = pop_val();
  387.         val1 = pop_val();
  388.         op   = pop_op();
  389.  
  390.         switch (op) {
  391.         case PLUS_TOK:        push_val(val1 + val2);    break;
  392.         case MINUS_TOK:        push_val(val1 - val2);    break;
  393.         case STAR_TOK:        push_val(val1 * val2);    break;
  394.         case DIV_TOK:        push_val((long)(val2?(val1/val2):0));
  395.                     break;
  396.         case MOD_TOK:        push_val(val1 % val2);    break;
  397.         case AND_TOK:        push_val(val1 &